<?php
namespace Pinenut;
use Pinenut\Response\LiteException;
/**
 * Ответ действия
 * 
 * @author kosh
 *
 */
class Response {
	public $content;
	public $data = [];
	public $key = null;

	/**
	 * @var null|\Exception
	 */
	public $exception = null;
	
	protected $options = [
		'noRender' => false,
		'noCache' => false
	];
	
	/**
	 * Значения, устанавливаемые в заголовок
	 * Действенно только для корневого действия
	 * @var unknown
	 */
	protected $_header = [];
	
	/**
	 * Хранилище дополнительной информации, 
	 * которая поднимается наверх в иерархии вызовов HMVC
	 * 
	 * @var array
	 */
	protected $channels = [];
	
	/**
	 * Хранилище команд, для накатывания в родителя после восстановаления из кеш
	 * @var array
	 */
	protected $channelsCommands = [];
	
	
	function __toString() {
		return (string)$this->content;
	}
	
	function data() {
		return $this->data;
	}

	function setData($data) {
		return $this->data = $data;
	}	
	function __get($name) {
		if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }
	}
	
	function __set($name, $value) {
		return $this->data[$name] = $value;
	}
	
	function noRender($value = null) {
		if (null !== $value) {
			$this->options['noRender'] = $value;
		}
		return $this->options['noRender'];
	}

	function noCache($value = null) {
		if (null !== $value) {
			$this->options['noCache'] = $value;
		}
		return $this->options['noCache'];
	}
	
	/**
	 * Добавляем данные в канал, в конец массива
	 * @param string $key
	 * @param $value
	 */
	function append($key, $value) {
		//$this->channels[$key] = isset($this->channels[$key])?(array)$this->channels[$key]:array();
		//array_push($this->channels[$key], $value);
		if (!isset($this->channels[$key]) || !is_array($this->channels[$key])) {
			$this->channels[$key] = [];
		}
		$this->channels[$key][] = $value;
		$this->channelsCommands[] = array('append', $key, $value, null);
	}
	
	function prepend($key, $value) {
		if (!isset($this->channels[$key]) || !is_array($this->channels[$key])) {
			$this->channels[$key] = [];
		}
//		$this->channels[$key] = isset($this->channels[$key])?(array)$this->channels[$key]:array();
		array_unshift($this->channels[$key], $value);
		$this->channelsCommands[] = array('prepend', $key, $value, null);
	}
	
	function offset($key, $value, $offset) {
//		$this->channels[$key] = isset($this->channels[$key])?(array)$this->channels[$key]:array();
		$this->channels[$key][$offset] = $value;
		$this->channelsCommands[] = array('offset', $key, $value, $offset);
	}
	
	function set($key, $value) {
		$this->channels[$key] = $value;
		$this->channelsCommands[] = array('set', $key, $value, null);
	}
	
	function get($key) {
		return @$this->channels[$key];
	}
	
	function getCommands() {
		return @$this->channelsCommands;
	}
	
	/**
	 * Проигрываем команды из дочернего запроса у себя
	 * @param array $commands
	 */
	function playCommands(array $commands) {
		foreach ($commands as $command) {
			$method = $command[0];
			switch ($method) {
				case 'append':
					$this->append($command[1], $command[2], $command[3]);
					break;
				case 'prepend':
					$this->prepend($command[1], $command[2], $command[3]);
					break;
				case 'offset':
					$this->offset($command[1], $command[2], $command[3]);
					break;
				case 'set':
					$this->set($command[1], $command[2], $command[3]);
					break;
			}
		}
	}
	
	function setException(\Exception $exception) {
		$this->code($exception->getCode(), $exception->getMessage());
		// убрал потому как ацкий ад в кеше начинается, тормоза
		// TODO: сделать суррогат исключения
		
		$lite = new LiteException($exception->getMessage(), $exception->getCode(), $exception->getPrevious());
		$lite->setFile($exception->getFile());
		$lite->setLine($exception->getLine());
		$lite->setString((string)$exception);
		
		$trace = $exception->getTrace();
		foreach ($trace as &$t) {
			$t['args'] = array_keys($t['args']);
		}
		$lite->setTrace($trace);
		
		$this->exception = $lite;
	}
	
	
	function playChannels($requestKey = null) {
		// получаем список дочерних текущему запросу запросов
		$children = \Dispatcher::$currentContext->getChildrenResponses($requestKey);
		$commands = array();
		foreach ($children as $childResponse) {
			// для каждого дочернего действия берём его готовый ответ и накатываем его на текущий
			$commands = array_merge($commands, $childResponse->getCommands());
			
		}
		$this->playCommands($commands);
	}
	
	
	/**
	 * Отправляем заголовок 
	 * 
	 * @param string $str
	 * @param string $replace
	 */
	function header($str, $replace = true, $code = null) {
		$this->_header[] = [$str, $replace, $code];
	}
	
	/**
	 * Устанавливаем код ответа
	 * 
	 * @param int|string $code
	 * @param string $str
	 */
	function code($code, $str = null) {
		$protocol = isset($_SERVER ["SERVER_PROTOCOL"])?$_SERVER ["SERVER_PROTOCOL"]:'HTTP/1.1';
		if (!is_array($code)) {
			$this->header($protocol . ' ' . $code . ' '. $str, true, $code);
		}
	}
	
	function headers() {
		return $this->_header;
	}
	
}